/*
 * @Author: sparkstudiosju 419785598@qq.com
 * @Date: 2025-08-29 13:12:04
 * @LastEditors: sparkstudiosju 419785598@qq.com
 * @LastEditTime: 2025-08-29 13:12:04
 * @FilePath: /SJUDEMO_HAL/src/seg7.c
 * @Description: 数码管驱动 - 通过74HC595驱动
 * 
 * Copyright (c) 2025 by ${git_name_email}, All Rights Reserved. 
 */
#include "seg7.h"

// ==================== 段码表定义 ====================
// 数字 0-9 的段码 (共阴驱动)
// 段码映射: A->Q1, B->Q2, C->Q0, D->Q6
//           E->Q5, F->Q3, G->Q4, DP->Q7
const uint8_t seg7_digit_table[10] = {
    0x3F,  // 0: ABCDEF (0011 1111)
    0x06,  // 1: BC (0000 0110)
    0x5B,  // 2: ABDEG (0101 1011)
    0x4F,  // 3: ABCDG (0100 1111) - 恢复原始段码
    0x66,  // 4: BCFG (0110 0110)
    0x6D,  // 5: ACDFG (0110 1101)
    0x7D,  // 6: ACDFEG (0111 1101)
    0x07,  // 7: ABC (0000 0111)
    0x7F,  // 8: ABCDEFG (0111 1111)
    0x6F   // 9: ABCDFG (0110 1111)
};

// 字母 A-F 的段码 (共阴驱动)
// 段码映射: A->Q1, B->Q2, C->Q0, D->Q6
//           E->Q5, F->Q3, G->Q4, DP->Q7
const uint8_t seg7_letter_table[6] = {
    0x77,  // A: ABCEFG (0111 0111)
    0x7C,  // B: CDEFG (0111 1100)
    0x39,  // C: ADEF (0011 1001)
    0x5E,  // D: BCDEG (0101 1110)
    0x79,  // E: ADEFG (0111 1001)
    0x71   // F: AEFG (0111 0001)
};

// ==================== 新连线段码表 ====================
// 数字 0-9 的段码 (新连线关系)
// 段码映射: A->Q6, B->Q5, C->Q3, D->Q1
//           E->Q2, F->Q0, G->Q7, DP->Q4
// 该段码只适用于数码管上下颠倒安装错误的情况
// 生成时间: 2025/8/29 16:32:56
// 驱动方式: 共阴
// 数码管段码表 (包含数字0-9和自定义字符)
const unsigned char seg7_digit_table_new0ld[27] = {
    0x6F ,// 0,
    0x05 ,// 1,
    0xE6 ,// 2,
    0xC7 ,// 3,
    0x8D ,// 4,
    0xCB ,// 5,
    0xEB ,// 6,
    0x07 ,// 7,
    0xEF ,// 8,
    0xCF ,// 9,
    0xAF ,// A,
    0xE9 ,// b,
    0x47 ,// c,
    0xE5 ,// d,
    0xEA ,// e,
    0xAA ,// f,
    0x80 // -
};
const unsigned char seg7_digit_table_new[27] = {
    0x6F, // 0: ¶Ρ,b,c,d,e,fÁÁ
    0x05, // 1: ¶΢,cÁÁ
    0x76, // 2: ¶Ρ,b,g,e,dÁÁ
    0x57, // 3: ¶Ρ,b,g,c,dÁÁ
    0x1D, // 4: ¶Φ,g,b,cÁÁ
    0x5B, // 5: ¶Ρ,f,g,c,dÁÁ
    0x7B, // 6: ¶Ρ,f,g,c,d,eÁÁ
    0x07, // 7: ¶Ρ,b,cÁÁ
    0x7F, // 8: ȫ¶΁Á
    0x5F, // 9: ¶Ρ,b,c,d,f,gÁÁ
    0x3F, // A: ¶Ρ,b,c,e,f,gÁÁ
    0x79, // b: ¶Σ,d,e,f,gÁÁ
    0x6A, // C: ¶Ρ,d,e,fÁÁ
    0x75, // d: ¶΢,c,d,e,gÁÁ
    0x7A, // E: ¶Ρ,d,e,f,gÁÁ
    0x3A  // F: ¶Ρ,e,f,gÁÁ
};



// 字母 A-F 的段码 (新连线关系)
const uint8_t seg7_letter_table_new[6] = {
    0xEE,  // A: ABCEFG (1110 1110)
    0xC3,  // B: CDEFG (1100 0011)
    0x6C,  // C: ADEF (0110 1100)
    0xA9,  // D: BCDEG (1010 1001)
    0xEC,  // E: ADEFG (1110 1100)
    0xE4   // F: AEFG (1110 0100)
};

// ==================== 私有函数声明 ====================
static void SEG7_ShiftOut(uint8_t data);
static void SEG7_Latch(void);

// ==================== 74HC595通信函数 ====================

/**
 * @brief 向74HC595发送一个字节数据
 * @param data: 要发送的数据
 * @retval None
 */
static void SEG7_ShiftOut(uint8_t data) {
    // 从高位到低位发送
    for (int i = 7; i >= 0; i--) {
        // 设置数据位
        if (data & (1 << i)) {
            SEG7_DS_HIGH();
        } else {
            SEG7_DS_LOW();
        }
        
        // 产生移位时钟脉冲
        SEG7_SHCP_LOW();
        // 这里可以添加小延时确保数据稳定
        for (volatile int j = 0; j < 10; j++);
        SEG7_SHCP_HIGH();
        for (volatile int j = 0; j < 10; j++);
    }
}

/**
 * @brief 锁存输出 - 将移位寄存器的数据输出到输出寄存器
 * @param None
 * @retval None
 */
static void SEG7_Latch(void) {
    SEG7_STCP_LOW();
    // 延时确保数据稳定
    for (volatile int i = 0; i < 20; i++);
    SEG7_STCP_HIGH();
    for (volatile int i = 0; i < 20; i++);
}

// ==================== 公共函数实现 ====================

/**
 * @brief 初始化数码管和74HC595
 * @param None
 * @retval None
 */
void SEG7_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    // 使能GPIOB时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();
    
    // 配置74HC595控制引脚为推挽输出
    GPIO_InitStruct.Pin = SEG7_SHCP_PIN | SEG7_STCP_PIN | SEG7_DS_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(SEG7_SHCP_GPIO_PORT, &GPIO_InitStruct);
    
    // 初始化引脚状态
    SEG7_SHCP_LOW();
    SEG7_STCP_LOW();
    SEG7_DS_LOW();
    
    // 清除显示
    SEG7_Clear();
}

/**
 * @brief 显示数字 0-9
 * @param digit: 要显示的数字 (0-9)
 * @retval None
 */
void SEG7_DisplayDigit(uint8_t digit) {
    if (digit > 9) {
        digit = 0;  // 超出范围显示0
    }
    
    uint8_t segment_code = seg7_digit_table[digit];
    SEG7_ShiftOut(segment_code);
    SEG7_Latch();
}

/**
 * @brief 显示字母 A-F
 * @param letter: 要显示的字母 (0-5 对应 A-F)
 * @retval None
 */
void SEG7_DisplayLetter(uint8_t letter) {
    if (letter > 5) {
        letter = 0;  // 超出范围显示A
    }
    
    uint8_t segment_code = seg7_letter_table[letter];
    SEG7_ShiftOut(segment_code);
    SEG7_Latch();
}

/**
 * @brief 显示自定义段码
 * @param segment_code: 自定义的段码
 * @retval None
 */
void SEG7_DisplayCustom(uint8_t segment_code) {
    SEG7_ShiftOut(segment_code);
    SEG7_Latch();
}

/**
 * @brief 清除显示
 * @param None
 * @retval None
 */
void SEG7_Clear(void) {
    SEG7_ShiftOut(0x00);  // 所有段都不亮
    SEG7_Latch();
}

/**
 * @brief 测试显示 - 循环显示所有数字和字母
 * @param None
 * @retval None
 */
void SEG7_Test(void) {
    // 测试数字显示
    for (int i = 0; i < 10; i++) {
        SEG7_DisplayDigit(i);
        HAL_Delay(500);
    }
    
    // 测试字母显示
    for (int i = 0; i < 6; i++) {
        SEG7_DisplayLetter(i);
        HAL_Delay(500);
    }
    
    // 清除显示
    SEG7_Clear();
}

// ==================== 新连线函数实现 ====================

/**
 * @brief 使用新段码表显示数字 0-9
 * @param digit: 要显示的数字 (0-9)
 * @retval None
 */
void SEG7_DisplayDigitNew(uint8_t digit) {
    if (digit > 9) {
        digit = 0;  // 超出范围显示0
    }
    
    uint8_t segment_code = seg7_digit_table_new[digit];
    SEG7_ShiftOut(segment_code);
    SEG7_Latch();
}

/**
 * @brief 使用新段码表显示字母 A-F
 * @param letter: 要显示的字母 (0-5 对应 A-F)
 * @retval None
 */
void SEG7_DisplayLetterNew(uint8_t letter) {
    if (letter > 5) {
        letter = 0;  // 超出范围显示A
    }
    
    uint8_t segment_code = seg7_letter_table_new[letter];
    SEG7_ShiftOut(segment_code);
    SEG7_Latch();
}

/**
 * @brief 使用新段码表测试显示 - 循环显示所有数字和字母
 * @param None
 * @retval None
 */
void SEG7_TestNew(void) {
    // 测试数字显示
    for (int i = 0; i < 10; i++) {
        SEG7_DisplayDigitNew(i);
        HAL_Delay(500);
    }
    
    // 测试字母显示
    for (int i = 0; i < 6; i++) {
        SEG7_DisplayLetterNew(i);
        HAL_Delay(500);
    }
    
    // 清除显示
    SEG7_Clear();
}
